import * as vscode from "vscode";
import { colors } from "./colors";
import { mirServer, MirServerProvider } from "./extension";

class ColorDecorationItem {
  groupRegex: RegExp;
  itemRegex: RegExp;
  blockDecorationType: vscode.TextEditorDecorationType;
  constructor(groupRegex: RegExp, itemRegex: RegExp) {
    this.groupRegex = groupRegex;
    this.itemRegex = itemRegex;
    this.blockDecorationType = vscode.window.createTextEditorDecorationType({
      before: {
        contentText: " ",
        width: "10x",
        height: "10x",
        margin: "0 2px 0 0",
      },
      rangeBehavior: vscode.DecorationRangeBehavior.ClosedClosed,
    });
  }

  render(editor: vscode.TextEditor, option: { renderText: boolean; renderBlock: boolean }) {
    if (!option.renderBlock && !option.renderText) {
      return;
    }
    const text = editor.document.getText();
    if (!text) {
      return;
    }

    const list = this.findGroup(text);
    if (option.renderBlock) {
      const colorRanges: vscode.DecorationOptions[] = list.map((item) => {
        const index = item.group.index + item.value.index;
        const startPos = editor.document.positionAt(index);
        // 色块装饰器
        return {
          range: new vscode.Range(startPos, startPos),
          renderOptions: {
            before: {
              contentText: "■",
              color: item.color.hex,
            },
          },
        };
      });
      editor.setDecorations(this.blockDecorationType, colorRanges);
    }

    if (option.renderText) {
      list.forEach((item) => {
        const index = item.group.index + item.value.index;
        const startPos = editor.document.positionAt(index);
        const endPos = editor.document.positionAt(index + item.value[0].length);
        const range = new vscode.Range(startPos, endPos);
        const type = vscode.window.createTextEditorDecorationType({
          // backgroundColor: "#ffffff",
          color: item.color.hex,
          rangeBehavior: vscode.DecorationRangeBehavior.ClosedClosed,
        });
        editor.setDecorations(type, [range]);
      });
    }
  }

  findGroup(text: string) {
    let result: RegExpExecArray | null;
    const list = [];
    while ((result = this.groupRegex.exec(text)) !== null) {
      list.push(...this.findItems(result));
    }
    return list;
  }

  findItems(execArray: RegExpExecArray) {
    const text = execArray[0];
    let result: RegExpExecArray | null;
    const list = [];
    while ((result = this.itemRegex.exec(text)) !== null) {
      const color = colors.find((color) => color.number === result![0]);
      if (color) {
        list.push({ group: execArray, value: result, color });
      }
    }
    return list;
  }
}

const colorBlockDecorationList = [new ColorDecorationItem(/autocolor=\d+(,\d+)*/gi, /\d+/g), new ColorDecorationItem(/scolor=\d+/gi, /\d+/g)];

export class ColorDecorationProvider implements MirServerProvider {
  enableColorBlock: boolean = true;
  enableColorText: boolean = true;
  updateDecorations(editor: vscode.TextEditor) {
    colorBlockDecorationList.forEach((item) =>
      item.render(editor, {
        renderText: this.enableColorText,
        renderBlock: this.enableColorBlock,
      })
    );
  }
  activeEditor?: vscode.TextEditor;
  activate() {
    const config = vscode.workspace.getConfiguration("mir-script-language");
    this.enableColorBlock = !!config.get("enable-color-block-decoration");
    this.enableColorText = !!config.get("enable-color-text-decoration");
    this.activeEditor = vscode.window.activeTextEditor;
    if (this.activeEditor) {
      this.updateDecorations(this.activeEditor);
    }

    mirServer.context.subscriptions.push(
      vscode.window.onDidChangeActiveTextEditor((editor) => {
        if (!editor || editor.document.languageId !== "mirtxt") {
          return;
        }
        this.activeEditor = editor;
        this.updateDecorations(this.activeEditor);
      }),
      vscode.workspace.onDidChangeTextDocument((e: vscode.TextDocumentChangeEvent) => {
        if (e.document !== this.activeEditor?.document) {
          return;
        }
        this.updateDecorations(this.activeEditor);
      })
    );
  }
}
